package cn.iocoder.yudao.module.reading.service.user;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.reading.controller.app.user.vo.UserSoftDeletedPageReqVO;
import cn.iocoder.yudao.module.reading.controller.app.user.vo.UserSoftDeletedRespVO;
import cn.iocoder.yudao.module.reading.controller.app.user.vo.UserStatsOverviewRespVO;
import cn.iocoder.yudao.module.reading.dal.dataobject.stats.UserReadingStatsDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.user.UserDO;
import cn.iocoder.yudao.module.reading.dal.mysql.stats.UserReadingStatsMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.user.UserMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.user.UserSettingsMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.recyclebin.UserRecycleBinMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.punch.PunchRecordMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.punch.PunchBookMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.record.ReadingRecordMapper;
import cn.iocoder.yudao.module.reading.service.favorite.FavoriteService;
import cn.iocoder.yudao.module.reading.service.recording.RecordingService;
import cn.iocoder.yudao.module.reading.dal.dataobject.punch.PunchBookDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.punch.PunchRecordDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.record.ReadingRecordDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.recyclebin.UserRecycleBinDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.user.UserSettingsDO;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.collection.CollUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants.USER_NOT_EXISTS;
import static cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants.USER_PASSWORD_INCORRECT;

/**
 * 用户 Service 实现类
 *
 * @author 李晨
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private UserReadingStatsMapper userReadingStatsMapper;

    @Resource
    private FavoriteService favoriteService;

    @Resource
    private RecordingService recordingService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserSettingsMapper userSettingsMapper;

    @Resource
    private UserRecycleBinMapper userRecycleBinMapper;

    @Resource
    private PunchRecordMapper punchRecordMapper;

    @Resource
    private PunchBookMapper punchBookMapper;

    @Resource
    private ReadingRecordMapper readingRecordMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public UserStatsOverviewRespVO getUserStatsOverview(Long userId) {
        log.info("获取用户统计概览，用户ID: {}", userId);

        UserStatsOverviewRespVO result = new UserStatsOverviewRespVO();

        // 1. 获取阅读统计数据
        UserReadingStatsDO readingStats = userReadingStatsMapper.selectByUserId(userId);
        if (readingStats != null) {
            result.setTotalPunchDays(readingStats.getTotalPunchDays());
            result.setTotalReadBooks(readingStats.getTotalReadBooks());
            result.setCurrentStreak(readingStats.getCurrentStreak());
            result.setMaxStreak(readingStats.getMaxStreak());
        } else {
            // 如果没有统计数据，设置默认值
            result.setTotalPunchDays(0);
            result.setTotalReadBooks(0);
            result.setCurrentStreak(0);
            result.setMaxStreak(0);
        }

        // 2. 获取收藏数量
        try {
            Long totalFavorites = favoriteService.countUserFavorites(userId, null);
            result.setTotalFavorites(totalFavorites != null ? totalFavorites.intValue() : 0);
        } catch (Exception e) {
            log.warn("获取用户收藏数量失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            result.setTotalFavorites(0);
        }

        // 3. 获取配音数量
        try {
            Long totalRecordings = recordingService.countUserRecordings(userId);
            result.setTotalRecordings(totalRecordings != null ? totalRecordings.intValue() : 0);
        } catch (Exception e) {
            log.warn("获取用户配音数量失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            result.setTotalRecordings(0);
        }

        // 4. 获取班级相关数据（暂时设置为0，等班级模块完善后再实现）
        result.setJoinedClasses(0);
        result.setCompletedAssignments(0);

        log.info("用户统计概览获取成功，用户ID: {}, 结果: {}", userId, result);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logoutAccount(Long userId) {
        log.info("开始注销用户账号（软删除），用户ID: {}", userId);

        try {
            // 1. 检查用户是否存在
            UserDO user = userMapper.selectById(userId);
            if (user == null) {
                log.warn("用户不存在，无法注销，用户ID: {}", userId);
                throw new RuntimeException("用户不存在");
            }

            // 2. 为用户名添加删除标识，避免唯一约束冲突（注释掉手机号处理）
            String timestamp = String.valueOf(System.currentTimeMillis());
            String originalUsername = user.getUsername();
            // String originalPhone = user.getPhone(); // 注释掉手机号获取

            // 构建带删除标识的用户名
            String deletedUsername = originalUsername + "_DELETED_" + timestamp;
            // String deletedPhone = originalPhone != null ? originalPhone + "_DELETED_" + timestamp : null; // 注释掉手机号处理

            // 更新用户基本信息，添加删除标识
            UserDO updateUser = new UserDO();
            updateUser.setId(userId);
            updateUser.setUsername(deletedUsername);
            // updateUser.setPhone(deletedPhone); // 注释掉手机号设置
            userMapper.updateById(updateUser);
            log.info("为用户添加删除标识成功，用户ID: {}, 原用户名: {}, 新用户名: {}", userId, originalUsername, deletedUsername);

            // 3. 软删除用户相关数据
            // 3.1 软删除用户统计数据
            try {
                userReadingStatsMapper.deleteByUserId(userId);
                log.info("软删除用户统计数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户统计数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.2 软删除用户收藏数据
            try {
                favoriteService.clearUserFavorites(userId, null);
                log.info("软删除用户收藏数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户收藏数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.3 软删除用户设置数据
            try {
                userSettingsMapper.deleteByUserId(userId);
                log.info("软删除用户设置数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户设置数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.4 软删除用户回收站数据
            try {
                userRecycleBinMapper.deleteByUserId(userId);
                log.info("软删除用户回收站数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户回收站数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.5 软删除用户打卡数据
            try {
                // 先软删除打卡绘本关联数据
                punchBookMapper.deleteByUserId(userId);
                // 再软删除打卡记录
                punchRecordMapper.deleteByUserId(userId);
                log.info("软删除用户打卡数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户打卡数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.6 软删除用户阅读记录
            try {
                readingRecordMapper.deleteByUserId(userId);
                log.info("软删除用户阅读记录成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户阅读记录失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3.7 软删除用户配音数据
            try {
                // RecordingService没有删除所有用户配音的方法，暂时跳过
                // recordingService.deleteAllUserRecordings(userId);
                log.info("跳过软删除用户配音数据，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("软删除用户配音数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 4. 最后软删除用户基本信息（MyBatis Plus会自动处理软删除）
            userMapper.deleteById(userId);
            log.info("软删除用户基本信息成功，用户ID: {}", userId);

            log.info("用户账号注销完成（软删除），用户ID: {}, 原用户名: {}", userId, originalUsername);
        } catch (Exception e) {
            log.error("用户账号注销失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            throw new RuntimeException("账号注销失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAccount(Long userId, String password, String reason) {
        log.info("开始删除用户账号（软删除），用户ID: {}, 原因: {}", userId, reason);

        try {
            // 1. 检查用户是否存在并验证密码
            UserDO user = userMapper.selectById(userId);
            if (user == null) {
                log.warn("用户不存在，无法删除，用户ID: {}", userId);
                throw exception(USER_NOT_EXISTS);
            }

            // 2. 验证密码
            if (!passwordEncoder.matches(password, user.getPassword())) {
                log.warn("密码错误，用户ID: {}", userId);
                throw exception(USER_PASSWORD_INCORRECT);
            }

            // 3. 调用软删除逻辑
            logoutAccount(userId);

            log.info("用户账号删除完成（软删除），用户ID: {}, 原因: {}", userId, reason);
        } catch (Exception e) {
            log.error("用户账号删除失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            throw new RuntimeException("账号删除失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void permanentDeleteAccount(Long userId, String reason) {
        log.info("开始永久删除用户账号（硬删除），用户ID: {}, 原因: {}", userId, reason);

        try {
            // 1. 检查用户是否存在（包括已软删除的用户）
            UserDO user = userMapper.selectById(userId);
            if (user == null) {
                log.warn("用户不存在，无法永久删除，用户ID: {}", userId);
                throw exception(USER_NOT_EXISTS);
            }

            // 2. 硬删除用户相关数据（使用物理删除）
            // 2.1 硬删除用户统计数据
            try {
                // 使用物理删除，绕过软删除机制
                userReadingStatsMapper.delete(new LambdaQueryWrapperX<UserReadingStatsDO>()
                        .eq(UserReadingStatsDO::getUserId, userId));
                log.info("硬删除用户统计数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户统计数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.2 硬删除用户收藏数据
            try {
                // 这里需要实现真正的硬删除逻辑
                favoriteService.clearUserFavorites(userId, null);
                log.info("硬删除用户收藏数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户收藏数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.3 硬删除用户设置数据
            try {
                // 使用物理删除，绕过软删除机制
                userSettingsMapper.delete(new LambdaQueryWrapperX<UserSettingsDO>()
                        .eq(UserSettingsDO::getUserId, userId));
                log.info("硬删除用户设置数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户设置数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.4 硬删除用户回收站数据
            try {
                // 使用物理删除，绕过软删除机制
                userRecycleBinMapper.delete(new LambdaQueryWrapperX<UserRecycleBinDO>()
                        .eq(UserRecycleBinDO::getUserId, userId));
                log.info("硬删除用户回收站数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户回收站数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.5 硬删除用户打卡数据
            try {
                // 先查询用户的所有打卡记录ID
                List<PunchRecordDO> punchRecords = punchRecordMapper.selectList(
                        new LambdaQueryWrapperX<PunchRecordDO>()
                                .eq(PunchRecordDO::getUserId, userId));

                // 删除打卡绘本关联数据
                if (!punchRecords.isEmpty()) {
                    List<Long> punchIds = punchRecords.stream()
                            .map(PunchRecordDO::getId)
                            .collect(java.util.stream.Collectors.toList());
                    punchBookMapper.delete(new LambdaQueryWrapperX<PunchBookDO>()
                            .in(PunchBookDO::getPunchId, punchIds));
                }

                // 再硬删除打卡记录
                punchRecordMapper.delete(new LambdaQueryWrapperX<PunchRecordDO>()
                        .eq(PunchRecordDO::getUserId, userId));
                log.info("硬删除用户打卡数据成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户打卡数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.6 硬删除用户阅读记录
            try {
                readingRecordMapper.delete(new LambdaQueryWrapperX<ReadingRecordDO>()
                        .eq(ReadingRecordDO::getUserId, userId));
                log.info("硬删除用户阅读记录成功，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户阅读记录失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 2.7 硬删除用户配音数据
            try {
                // RecordingService没有删除所有用户配音的方法，暂时跳过
                // recordingService.permanentDeleteAllUserRecordings(userId);
                log.info("跳过硬删除用户配音数据，用户ID: {}", userId);
            } catch (Exception e) {
                log.warn("硬删除用户配音数据失败，用户ID: {}, 错误: {}", userId, e.getMessage());
            }

            // 3. 最后硬删除用户基本信息（使用物理删除）
            userMapper.delete(new LambdaQueryWrapperX<UserDO>()
                    .eq(UserDO::getId, userId));
            log.info("硬删除用户基本信息成功，用户ID: {}", userId);

            log.info("用户账号永久删除完成（硬删除），用户ID: {}, 原因: {}", userId, reason);
        } catch (Exception e) {
            log.error("用户账号永久删除失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            throw new RuntimeException("账号永久删除失败: " + e.getMessage());
        }
    }

    @Override
    public PageResult<UserSoftDeletedRespVO> getSoftDeletedUserPage(UserSoftDeletedPageReqVO pageReqVO) {
        log.info("分页查询已软删除用户，查询条件: {}", pageReqVO);

        // 查询已软删除的用户
        PageResult<UserDO> pageResult = userMapper.selectSoftDeletedPage(pageReqVO);

        // 转换为响应VO
        return BeanUtils.toBean(pageResult, UserSoftDeletedRespVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreSoftDeletedUser(Long userId, String reason) {
        log.info("开始恢复软删除用户，用户ID: {}, 原因: {}", userId, reason);

        try {
            // 1. 检查用户是否存在（包括已软删除的用户）
            UserDO user = userMapper.selectById(userId);
            if (user == null) {
                log.warn("用户不存在，无法恢复，用户ID: {}", userId);
                throw exception(USER_NOT_EXISTS);
            }

            // 2. 检查用户是否已被软删除
            if (!user.getDeleted()) {
                log.warn("用户未被删除，无需恢复，用户ID: {}", userId);
                throw new RuntimeException("用户未被删除，无需恢复");
            }

            // 3. 恢复用户名（移除删除标识，注释掉手机号处理）
            String currentUsername = user.getUsername();
            // String currentPhone = user.getPhone(); // 注释掉手机号获取
            String originalUsername = currentUsername;
            // String originalPhone = currentPhone; // 注释掉手机号处理

            // 如果用户名包含删除标识，则恢复原始用户名
            if (currentUsername != null && currentUsername.contains("_DELETED_")) {
                originalUsername = currentUsername.substring(0, currentUsername.indexOf("_DELETED_"));
                log.info("恢复用户名，用户ID: {}, 当前用户名: {}, 原始用户名: {}", userId, currentUsername, originalUsername);
            }

            // 注释掉手机号恢复逻辑
            // if (currentPhone != null && currentPhone.contains("_DELETED_")) {
            //     originalPhone = currentPhone.substring(0, currentPhone.indexOf("_DELETED_"));
            //     log.info("恢复手机号，用户ID: {}, 当前手机号: {}, 原始手机号: {}", userId, currentPhone, originalPhone);
            // }

            // 检查恢复后的用户名和手机号是否与现有用户冲突
            if (!originalUsername.equals(currentUsername)) {
                UserDO existingUser = userMapper.selectByUsername(originalUsername);
                if (existingUser != null && !existingUser.getId().equals(userId)) {
                    log.warn("恢复用户失败，用户名已被占用，用户ID: {}, 用户名: {}", userId, originalUsername);
                    throw new RuntimeException("恢复失败：用户名 '" + originalUsername + "' 已被其他用户使用");
                }
            }

            // 注释掉手机号重复性检查
            // if (originalPhone != null && !originalPhone.equals(currentPhone)) {
            //     UserDO existingUser = userMapper.selectByPhone(originalPhone);
            //     if (existingUser != null && !existingUser.getId().equals(userId)) {
            //         log.warn("恢复用户失败，手机号已被占用，用户ID: {}, 手机号: {}", userId, originalPhone);
            //         throw new RuntimeException("恢复失败：手机号 '" + originalPhone + "' 已被其他用户使用");
            //     }
            // }

            // 4. 恢复用户（将deleted字段设为false，并恢复原始用户名和手机号）
            UserDO updateUser = new UserDO();
            updateUser.setId(userId);
            updateUser.setDeleted(false);
            updateUser.setUsername(originalUsername);
            // updateUser.setPhone(originalPhone); // 注释掉手机号恢复
            userMapper.updateById(updateUser);

            log.info("用户恢复成功，用户ID: {}, 原因: {}, 恢复用户名: {}", userId, reason, originalUsername);
        } catch (Exception e) {
            log.error("用户恢复失败，用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            throw new RuntimeException("用户恢复失败: " + e.getMessage());
        }
    }

    @Override
    public UserDO getUser(Long id) {
        if (id == null) {
            return null;
        }
        return userMapper.selectById(id);
    }

    @Override
    public List<UserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(ids);
    }

}
